package com.yumeng.common.buss.area;

import com.yumeng.common.buss.area.dto.AreaDto;
import com.yumeng.common.buss.area.dto.TopAreaDto;
import com.yumeng.common.exception.YumengException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wxd
 * @date 2022/10/25 12:30
 */
@Slf4j
public class AreaHelper {

    @Getter
    private static boolean isInit = false;
    public synchronized static void init(CurrSysAreaInfo areaInfo){
        if (isInit){
            throw new YumengException("AreaHelper 重复初始化");
        }
        currSysAreaCode = areaInfo.getCurrSysAreaCode();
        currSysAreaName = areaInfo.getCurrSysAreaName();
        currSysAreaLevel = areaInfo.getCurrSysAreaLevel();
        currAreaBussMode = areaInfo.getCurrAreaBussMode();

        if (currSysAreaLevel == null || StringUtils.isBlank(currSysAreaCode) || StringUtils.isBlank(currSysAreaName) || currAreaBussMode == null){
            throw new YumengException("AreaHelper初始化失败");
        }

        AreaLevel currAreaLevel;
        if (SysAreaLevel.TOP.equals(currSysAreaLevel)){
            currAreaLevel = AreaLevel.TOP;
        }else if (SysAreaLevel.PROVINCE.equals(currSysAreaLevel)){
            currAreaLevel = AreaLevel.PROVINCE;
        }else {
            throw new YumengException("目前仅支持顶级、省级平台");
        }

        Integer targetLen = getLenByAreaLevel(currAreaLevel);
        if (!targetLen.equals(currSysAreaCode.length())){
            throw new YumengException("当前系统-地区编码与级别不符");
        }
        if (currSysAreaLevel.equals(SysAreaLevel.TOP) && !AreaConstants.AREA_CODE_TOP.equals(currSysAreaCode)){
            throw new YumengException("顶级地区编码目前只支持‘0’");
        }
        isInit = true;
        log.info("AreaHelper已加载，级别：{}，编码：{}，名称：{}，模式：{}", getCurrSysAreaLevel().getDesc(), getCurrSysAreaCode(), getCurrSysAreaName(), getCurrAreaBussMode());
    }

    private static void checkInit(){
        if (!isInit){
            throw new YumengException("当前地区信息未初始化");
        }
    }

    private static SysAreaLevel currSysAreaLevel;
    private static String currSysAreaCode;
    private static String currSysAreaName;
    private static AreaBussMode currAreaBussMode;

    public static SysAreaLevel getCurrSysAreaLevel() {
        checkInit();
        return currSysAreaLevel;
    }
    public static String getCurrSysAreaCode() {
        checkInit();
        return currSysAreaCode;
    }
    public static String getCurrSysAreaName() {
        checkInit();
        return currSysAreaName;
    }
    public static AreaBussMode getCurrAreaBussMode() {
        checkInit();
        return currAreaBussMode;
    }

    /**
     * 根据地区编码获取父级编码
     * @param areaCode
     * @return
     */
    public static String getParAreaCode(String areaCode){
        if (StringUtils.isBlank(areaCode)){
            throw new YumengException("地区编码不能为空");
        }
        int len = areaCode.length();
        if (AreaConstants.AREA_CODE_TOP.equals(areaCode)){
            return "";
        }else if (AreaLevel.PROVINCE.getLen().equals(len)){
            return AreaConstants.AREA_CODE_TOP;
        }else if (AreaLevel.CITY.getLen().equals(len)){
            return areaCode.substring(0, AreaLevel.PROVINCE.getLen());
        }else if (AreaLevel.DISTRICT.getLen().equals(len)){
            return areaCode.substring(0, AreaLevel.CITY.getLen());
        }else if (AreaLevel.SUBDISTRICT.getLen().equals(len)){
            return areaCode.substring(0, AreaLevel.DISTRICT.getLen());
        }else if (AreaLevel.VILLAGE.getLen().equals(len)){
            return areaCode.substring(0, AreaLevel.SUBDISTRICT.getLen());
        }else {
            throw new YumengException("地区编码长度异常：%s", areaCode);
        }
    }

    /**
     * 根据地区编码获取地区级别
     * @param areaCode
     * @return
     */
    public static AreaLevel getAreaLevel(String areaCode){
        if (StringUtils.isBlank(areaCode)){
            throw new YumengException("地区编码不能为空");
        }
        int len = areaCode.length();
        if (AreaConstants.AREA_CODE_TOP.equals(areaCode)){
            return AreaLevel.TOP;
        }else if (AreaLevel.PROVINCE.getLen().equals(len)){
            return AreaLevel.PROVINCE;
        }else if (AreaLevel.CITY.getLen().equals(len)){
            return AreaLevel.CITY;
        }else if (AreaLevel.DISTRICT.getLen().equals(len)){
            return AreaLevel.DISTRICT;
        }else if (AreaLevel.SUBDISTRICT.getLen().equals(len)){
            return AreaLevel.SUBDISTRICT;
        }else if (AreaLevel.VILLAGE.getLen().equals(len)){
            return AreaLevel.VILLAGE;
        }else {
            throw new YumengException("地区编码长度异常：%s", areaCode);
        }
    }

    /**
     * 根据地区级别获取地区长度
     * @param level
     * @return
     */
    public static Integer getLenByAreaLevel(AreaLevel level){
        if (!AreaLevel.UN_KNOW.equals(level)){
            return level.getLen();
        }else {
            throw new YumengException("地区级别异常：%s", level.getCode());
        }
    }

    /**
     * 根据地区级别获取地区编码字段名称
     * @param level
     * @return
     */
    public static String getAreaCodePropNameByLevel(AreaLevel level){
        if (AreaLevel.TOP.equals(level)) {
            throw new YumengException("顶级地区不参与业务流程");
        }else if (AreaLevel.PROVINCE.equals(level)) {
            //只有顶级地区的系统，才需要省级地区参与业务
            if (!SysAreaLevel.TOP.equals(getCurrSysAreaLevel())){
                throw new YumengException("省级地区不参与业务流程");
            }
            return AreaConstants.AREA_CODE_PROVINCE_PROP_NAME;
        }else if (AreaLevel.CITY.equals(level)) {
            return  AreaConstants.AREA_CODE_CITY_PROP_NAME;
        }else if (AreaLevel.DISTRICT.equals(level)) {
            return AreaConstants.AREA_CODE_DISTRICT_PROP_NAME;
        }else if (AreaLevel.SUBDISTRICT.equals(level)) {
            return AreaConstants.AREA_CODE_SUBDISTRICT_PROP_NAME;
        }else if (AreaLevel.VILLAGE.equals(level)) {
            return AreaConstants.VILLAGE_CODE_PROP_NAME;
        }else {
            throw new YumengException("地区级别异常");
        }
    }

    //region getAreaCodeByLevel

    /**
     * 根据地区级别获取地区编码
     * @param level
     * @param areaDto
     * @return
     */
    public static String getAreaCodeByLevel(AreaLevel level, AreaDto areaDto){
        return getAreaCodeByLevel(level, areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }

    /**
     * 根据地区级别获取地区编码
     * @param level
     * @param areaDto
     * @return
     */
    public static String getAreaCodeByLevel(AreaLevel level, TopAreaDto areaDto){
        return getAreaCodeByLevel(level, areaDto.getAreaCodeProvince(), areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }

    /**
     * 根据地区级别获取地区编码
     * @param level
     * @param areaCodeCity
     * @param areaCodeDistrict
     * @param areaCodeSubdistrict
     * @param villageCode
     * @return
     */
    public static String getAreaCodeByLevel(AreaLevel level, String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        String areaCode = getAreaCode(areaCodeCity, areaCodeDistrict, areaCodeSubdistrict, villageCode);
        int targetLen = getLenByAreaLevel(level);
        if (areaCode.length() < targetLen){
            throw new YumengException("地区编码与地区级别不匹配：%s-%d", areaCode, targetLen);
        }
        return areaCode.substring(0, targetLen);
    }

    /**
     * 根据地区级别获取地区编码
     * @param level
     * @param areaCodeProvince
     * @param areaCodeCity
     * @param areaCodeDistrict
     * @param areaCodeSubdistrict
     * @param villageCode
     * @return
     */
    public static String getAreaCodeByLevel(AreaLevel level, String areaCodeProvince, String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        String areaCode = getAreaCode(areaCodeProvince, areaCodeCity, areaCodeDistrict, areaCodeSubdistrict, villageCode);
        int targetLen = getLenByAreaLevel(level);
        if (areaCode.length() < targetLen){
            throw new YumengException("地区编码与地区级别不匹配：%s-%d", areaCode, targetLen);
        }
        return areaCode.substring(0, targetLen);
    }

    //endregion

    //region getAreaCode

    /**
     * 获取当前areaCode
     * @param areaCodeCity
     * @param areaCodeDistrict
     * @param areaCodeSubdistrict
     * @param villageCode
     * @return
     */
    public static String getAreaCode(String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        if (StringUtils.isNotBlank(villageCode)) {
            return villageCode;
        }else if (StringUtils.isNotBlank(areaCodeSubdistrict)) {
            return areaCodeSubdistrict;
        }else if (StringUtils.isNotBlank(areaCodeDistrict)) {
            return areaCodeDistrict;
        }else if (StringUtils.isNotBlank(areaCodeCity)) {
            return areaCodeCity;
        }else {
            return getCussSysTopAreaCode(SysAreaLevel.PROVINCE);
        }
    }

    /**
     * 获取当前areaCode
     * @param areaCodeProvince
     * @param areaCodeCity
     * @param areaCodeDistrict
     * @param areaCodeSubdistrict
     * @param villageCode
     * @return
     */
    public static String getAreaCode(String areaCodeProvince, String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        if (StringUtils.isNotBlank(villageCode)) {
            return villageCode;
        }else if (StringUtils.isNotBlank(areaCodeSubdistrict)) {
            return areaCodeSubdistrict;
        }else if (StringUtils.isNotBlank(areaCodeDistrict)) {
            return areaCodeDistrict;
        }else if (StringUtils.isNotBlank(areaCodeCity)) {
            return areaCodeCity;
        }else if (StringUtils.isNotBlank(areaCodeProvince)) {
            return areaCodeProvince;
        }else {
            return getCussSysTopAreaCode(SysAreaLevel.TOP);
        }
    }

    /**
     * 获取当前areaCode
     * @param areaDto
     * @return
     */
    public static String getAreaCode(AreaDto areaDto){
        return getAreaCode(areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }

    /**
     * 获取当前areaCode
     * @param areaDto
     * @return
     */
    public static String getAreaCode(TopAreaDto areaDto){
        return getAreaCode(areaDto.getAreaCodeProvince(), areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }

    /**
     * 根据地区编码获取areaCode列表
     * @param areaCode
     * @return
     */
    public static List<String> getAreaCodes(String areaCode){
        List<String> list = new ArrayList<>();
        if (StringUtils.isBlank(areaCode)){
            throw new YumengException("地区编码不能为空");
        }
        int len = areaCode.length();
        if (AreaLevel.VILLAGE.getLen().equals(len)) {
            list.add(areaCode);
            list.add(areaCode.substring(0,AreaLevel.SUBDISTRICT.getLen()));
            list.add(areaCode.substring(0,AreaLevel.DISTRICT.getLen()));
            list.add(areaCode.substring(0,AreaLevel.CITY.getLen()));
            list.add(areaCode.substring(0,AreaLevel.PROVINCE.getLen()));
        }else if (AreaLevel.SUBDISTRICT.getLen().equals(len)) {
            list.add(areaCode);
            list.add(areaCode.substring(0,AreaLevel.DISTRICT.getLen()));
            list.add(areaCode.substring(0,AreaLevel.CITY.getLen()));
            list.add(areaCode.substring(0,AreaLevel.PROVINCE.getLen()));
        }else if (AreaLevel.DISTRICT.getLen().equals(len)) {
            list.add(areaCode);
            list.add(areaCode.substring(0,AreaLevel.CITY.getLen()));
            list.add(areaCode.substring(0,AreaLevel.PROVINCE.getLen()));
        }else if (AreaLevel.CITY.getLen().equals(len)) {
            list.add(areaCode);
            list.add(areaCode.substring(0,AreaLevel.PROVINCE.getLen()));
        }else if (AreaLevel.PROVINCE.getLen().equals(len)) {
            list.add(areaCode);
        }else if (AreaConstants.AREA_CODE_TOP.equals(areaCode)) {
            if (!SysAreaLevel.TOP.equals(getCurrSysAreaLevel())){
                throw new YumengException("当前系统地区级别不匹配（地区编码为顶级时）");
            }
        }else{
            throw new YumengException("地区编码异常：%s", areaCode);
        }
        if (SysAreaLevel.TOP.equals(getCurrSysAreaLevel())){
            list.add(AreaConstants.AREA_CODE_TOP);
        }
        return list;
    }

    //endregion

    //region areaInfo

    public static AreaCodeInfo getAreaCodeInfo(String areaCode){
        String areaCodeProvince = "";
        String areaCodeCity = "";
        String areaCodeDistrict = "";
        String areaCodeSubdistrict = "";
        String villageCode = "";
        if (StringUtils.isNotBlank(areaCode)){
            int len = areaCode.length();
            if (AreaConstants.AREA_CODE_TOP.equals(areaCode)){
                //顶级编号 不做处理
            } else if (AreaLevel.PROVINCE.getLen().equals(len)){
                areaCodeProvince = areaCode;
            } else if (AreaLevel.CITY.getLen().equals(len)){
                areaCodeProvince = areaCode.substring(0,AreaLevel.PROVINCE.getLen());
                areaCodeCity = areaCode;
            }else if (AreaLevel.DISTRICT.getLen().equals(len)){
                areaCodeProvince = areaCode.substring(0,AreaLevel.PROVINCE.getLen());
                areaCodeCity = areaCode.substring(0,AreaLevel.CITY.getLen());
                areaCodeDistrict = areaCode;
            }else if (AreaLevel.SUBDISTRICT.getLen().equals(len)){
                areaCodeProvince = areaCode.substring(0,AreaLevel.PROVINCE.getLen());
                areaCodeCity = areaCode.substring(0,AreaLevel.CITY.getLen());
                areaCodeDistrict = areaCode.substring(0,AreaLevel.DISTRICT.getLen());
                areaCodeSubdistrict = areaCode;
            }else if (AreaLevel.VILLAGE.getLen().equals(len)){
                areaCodeProvince = areaCode.substring(0,AreaLevel.PROVINCE.getLen());
                areaCodeCity = areaCode.substring(0,AreaLevel.CITY.getLen());
                areaCodeDistrict = areaCode.substring(0,AreaLevel.DISTRICT.getLen());
                areaCodeSubdistrict = areaCode.substring(0,AreaLevel.SUBDISTRICT.getLen());
                villageCode = areaCode;
            }else{
                throw new YumengException("areaCode异常：%s", areaCode);
            }
        }else {
            throw new YumengException("areaCode为空");
        }
        return new AreaCodeInfo(areaCodeProvince, areaCodeCity, areaCodeDistrict, areaCodeSubdistrict, villageCode, areaCode);
    }

    //endregion

    //region 地区编码格式验证

    public static void checkAreaCodeFormat(AreaDto areaDto){
        checkAreaCodeFormat(null, areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }
    public static void checkAreaCodeFormat(TopAreaDto areaDto){
        checkAreaCodeFormat(areaDto.getAreaCodeProvince(), areaDto.getAreaCodeCity(), areaDto.getAreaCodeDistrict(), areaDto.getAreaCodeSubdistrict(), areaDto.getVillageCode());
    }
    public static void checkAreaCodeFormat(String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        checkAreaCodeFormat(null, areaCodeCity, areaCodeDistrict, areaCodeSubdistrict, villageCode);
    }
    public static void checkAreaCodeFormat(String areaCodeProvince, String areaCodeCity, String areaCodeDistrict, String areaCodeSubdistrict, String villageCode){
        if (StringUtils.isNotBlank(areaCodeProvince) && !AreaLevel.PROVINCE.getLen().equals(areaCodeProvince.length())){
            throw new YumengException("省编码长度异常：%s", areaCodeProvince);
        }
        if (StringUtils.isNotBlank(areaCodeCity) && !AreaLevel.CITY.getLen().equals(areaCodeCity.length())){
            if(StringUtils.isNotBlank(areaCodeProvince) && !areaCodeCity.startsWith(areaCodeProvince)){
                throw new YumengException("省、市编码上下级关系异常：%s-%s", areaCodeProvince, areaCodeCity);
            }
            throw new YumengException("市编码长度异常：%s", areaCodeCity);
        }
        if (StringUtils.isNotBlank(areaCodeDistrict) && !AreaLevel.DISTRICT.getLen().equals(areaCodeDistrict.length())){
            if(StringUtils.isNotBlank(areaCodeCity) && !areaCodeDistrict.startsWith(areaCodeCity)){
                throw new YumengException("市、区编码上下级关系异常：%s-%s", areaCodeCity, areaCodeDistrict);
            }
            throw new YumengException("区编码长度异常：%s", areaCodeDistrict);
        }
        if (StringUtils.isNotBlank(areaCodeSubdistrict) && !AreaLevel.SUBDISTRICT.getLen().equals(areaCodeSubdistrict.length())){
            if(StringUtils.isNotBlank(areaCodeDistrict) && !areaCodeSubdistrict.startsWith(areaCodeDistrict)){
                throw new YumengException("区、街道编码上下级关系异常：%s-%s", areaCodeDistrict, areaCodeSubdistrict);
            }
            throw new YumengException("街道编码长度异常：%s", areaCodeSubdistrict);
        }
        if (StringUtils.isNotBlank(villageCode) && !AreaLevel.VILLAGE.getLen().equals(villageCode.length())){
            if(StringUtils.isNotBlank(areaCodeSubdistrict) && !villageCode.startsWith(areaCodeSubdistrict)){
                throw new YumengException("街道、村编码上下级关系异常：%s-%s", areaCodeSubdistrict, villageCode);
            }
            throw new YumengException("村编码长度异常：%s", villageCode);
        }
    }

    //endregion

    //region private

    /**
     * 获取当前系统的最顶级地区编码
     *
     * @param topAreaLevel
     * @return
     */
    private static String getCussSysTopAreaCode(SysAreaLevel topAreaLevel){
        if (topAreaLevel.equals(getCurrSysAreaLevel())){
            return getCurrSysAreaCode();
        }else{
            throw new YumengException("当前系统地区级别异常");
        }
    }

    //endregion

}
